#include "PollPoller.h"
#include <map>
#include <sstream>
#include <sys/poll.h>
#include "Channel.h"
#include "DateTime.h"
#include "PlatLogger.h"
#include "Poller.h"
#include "Util.h"
namespace xncc {
namespace foundation {
    using namespace shared;
    PollPoller::PollPoller()  = default;
    PollPoller::~PollPoller() = default;

    void PollPoller::addChannel(const std::shared_ptr<Channel>& chnl)
    {
        Poller::addChannel(chnl);
        struct pollfd pfd = {};
        pfd.fd            = chnl->fd();
        pfd.events        = static_cast<short>(chnl->events());
        pfd.revents       = 0;
        pollfds_.push_back(pfd);
        int idx = static_cast<int>(pollfds_.size()) - 1;
        chnl->setIndex(idx);
        channels_[pfd.fd] = chnl;
    }
    void PollPoller::removeChannel(const std::shared_ptr<Channel>& chnl)
    {
        Poller::removeChannel(chnl);
        int fd = chnl->fd();
        if (unlikely(channels_.find(fd) == channels_.end())) {
            std::ostringstream oss;
            oss << "remove channel of fd = " << fd << ", but channel not exist";
            throw logic_exception(oss.str());
        }
        assert(channels_[fd] == chnl);
        int                  idx = chnl->index();
        const struct pollfd& pfd = pollfds_[static_cast<std::size_t>(idx)];
        if (unlikely(!(pfd.fd == -fd - 1 && pfd.events == chnl->events()))) {
            throw logic_exception("fd error");
        }
        size_t n = channels_.erase(fd);
        assert(n == 1);
        (void)n;
        if (static_cast<size_t>(idx) == pollfds_.size() - 1) {  // 最后一个元素 直接delete
            pollfds_.pop_back();
        }
        else {
            int channelAtEnd = pollfds_.back().fd;
            iter_swap(pollfds_.begin() + idx, pollfds_.end() - 1);  // 交换最后一个元素 和要删除的元素
            if (channelAtEnd < 0) {
                channelAtEnd = -channelAtEnd - 1;  // 不关注的事件 被设置为负值了 原始的fd 还原一下
            }
            channels_[channelAtEnd]->setIndex(idx);  // 更新索引 最后一个元素位置挪到 要删除的元素位置了
            pollfds_.pop_back();
        }
    }
    void PollPoller::updateChannel(const std::shared_ptr<Channel>& chnl)
    {
        // 使用裸指针 update如果是pending函数，有可能 ch已经因为断开而被移除和析构了
        // 存在崩溃风险，调整为智能指针的原因
        int fd = chnl->fd();
        if (unlikely(channels_.find(fd) == channels_.end())) {
            TRACE_ERROR << "channel may be remove because of disconnect"_s;
            return;
        }
        int            idx = chnl->index();
        struct pollfd& pfd = pollfds_[static_cast<std::size_t>(idx)];
        if (unlikely(!(pfd.fd == fd || pfd.fd == -fd - 1))) {
            throw logic_exception("fd error");
        }
        pfd.fd      = fd;
        pfd.events  = static_cast<short>(chnl->events());
        pfd.revents = 0;
        if (chnl->isNoneEvent()) {
            // ignore this pollfd
            pfd.fd = -fd - 1;
        }
    }
    void PollPoller::loopOnce(int waitUs)
    {
        int numEvents =
            ::poll(&*pollfds_.begin(), static_cast<nfds_t>(pollfds_.size()), waitUs / types::DateTime::MICROS_PER_MILL);
        int savedErrno = errno;
        if (numEvents > 0) {
            for (auto pfd = pollfds_.begin(); pfd != pollfds_.end() && numEvents > 0; ++pfd) {
                if (pfd->revents > 0) {
                    --numEvents;
                    validPfds_.push_back(*pfd);
                }
            }
            for (auto& pfd : validPfds_) {
                auto iter = channels_.find(pfd.fd);
                if (iter == channels_.end()) {
                    continue;  // handle exception
                }
                auto              channel = iter->second;
                const int         events  = pfd.revents;
                const auto        fd      = channel->fd();
                const auto        connId  = channel->connId();
                const auto* const type    = ChannelType::toString(channel->Type());
#if defined(__CYGWIN__)
                if (events & (POLLIN | POLLPRI)) {
                    channel->handleRead();
                }
#else
                if ((events & (POLLIN | POLLPRI | POLLRDHUP)) != 0) {
                    channel->handleRead();
                }
#endif
                if ((events & POLLHUP) && !(events & POLLIN)) {
                    if (channels_.find(fd) != channels_.end()) {
                        channel->handleClose(
                            getDisconnectedReason(savedErrno));  // 回调函数可能执行删除channel的操作 导致后续的操作失效
                    }
                    else {
                        TRACE_ERROR << "channel not exists POLLHUP channel:"_s << connId << " fd:"_s << fd
                                    << " channel_type:" << type;
                    }
                }
                if ((events & POLLNVAL) != 0) {}
                if ((events & (POLLERR | POLLNVAL)) != 0) {
                    if (channels_.find(fd) != channels_.end()) {
                        TRACE_ERROR << "POLLERR or POLLNVAL channel:"_s << connId << " fd:"_s << fd
                                    << " channel_type:" << type;
                        channel->handleError(
                            getDisconnectedReason(savedErrno));  // 回调函数可能执行删除channel的操作 导致后续的操作失效
                    }
                    else {
                        TRACE_ERROR << "channel not exists POLLERR or POLLNVAL channel:"_s << connId << " fd:"_s << fd
                                    << " channel_type:" << type;
                    }
                }
                if ((events & POLLOUT) != 0) {
                    if (channels_.find(fd) != channels_.end()) {
                        channel->handleWrite();
                    }
                    else {
                        TRACE_ERROR << "channel not exists POLLOUT channel:"_s << connId << " fd:"_s << fd
                                    << " channel_type:" << type;
                    }
                }
            }
            validPfds_.clear();
        }
        else if (numEvents == 0) {
        }
        else {
            if (savedErrno != EINTR) {
                errno = savedErrno;
                SYSTEM_ERROR << "PollPoller::poll()"_s;
            }
        }
    }

}  // namespace foundation
}  // namespace xncc